/// Copyright (c) 2005-2008, Simon Howard
/// Permission to use, copy, modify, and/or distribute this software for any purpose
/// with or without fee is hereby granted, provided that the above copyright notice
/// and this permission notice appear in all copies.
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
/// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
/// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
/// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
/// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
/// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
/// PERFORMANCE OF THIS SOFTWARE.

/// Compares two strings for equality.
///
/// # Arguments
///
/// * `string1` - A reference to the first string.
/// * `string2` - A reference to the second string.
///
/// # Returns
///
/// Returns `true` if the strings are equal, otherwise `false`.
pub fn string_equal(string1: &str, string2: &str) -> bool {
    string1 == string2
}

/// Compares two strings lexicographically.
///
/// # Arguments
///
/// * `string1` - A reference to the first string.
/// * `string2` - A reference to the second string.
///
/// # Returns
///
/// Returns:
/// * `-1` if `string1` is less than `string2`.
/// * `1` if `string1` is greater than `string2`.
/// * `0` if `string1` is equal to `string2`.
pub fn string_compare(string1: &str, string2: &str) -> i32 {
    match string1.cmp(string2) {
        std::cmp::Ordering::Less => -1,
        std::cmp::Ordering::Greater => 1,
        std::cmp::Ordering::Equal => 0,
    }
}

/// Compares two strings for equality, ignoring case.
///
/// # Arguments
///
/// * `string1` - A reference to the first string.
/// * `string2` - A reference to the second string.
///
/// # Returns
///
/// Returns `true` if the strings are equal (case-insensitive), otherwise `false`.
pub fn string_nocase_equal(string1: &str, string2: &str) -> bool {
    string_nocase_compare(string1, string2) == 0
}

/// Compares two strings lexicographically, ignoring case.
///
/// # Arguments
///
/// * `string1` - A reference to the first string.
/// * `string2` - A reference to the second string.
///
/// # Returns
///
/// Returns:
/// * `-1` if `string1` is less than `string2` (case-insensitive).
/// * `1` if `string1` is greater than `string2` (case-insensitive).
/// * `0` if `string1` is equal to `string2` (case-insensitive).
pub fn string_nocase_compare(string1: &str, string2: &str) -> i32 {
    let string1_chars = string1.chars().map(|c| c.to_ascii_lowercase());
    let string2_chars = string2.chars().map(|c| c.to_ascii_lowercase());

    for (c1, c2) in string1_chars.zip(string2_chars) {
        if c1 != c2 {
            return if c1 < c2 { -1 } else { 1 };
        }
    }

    // If one string is a prefix of the other, compare lengths.
    string1.len().cmp(&string2.len()).into()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_string_equal() {
        assert!(string_equal("hello", "hello"));
        assert!(!string_equal("hello", "world"));
    }

    #[test]
    fn test_string_compare() {
        assert_eq!(string_compare("apple", "banana"), -1);
        assert_eq!(string_compare("banana", "apple"), 1);
        assert_eq!(string_compare("apple", "apple"), 0);
    }

    #[test]
    fn test_string_nocase_equal() {
        assert!(string_nocase_equal("Hello", "hello"));
        assert!(!string_nocase_equal("Hello", "world"));
    }

    #[test]
    fn test_string_nocase_compare() {
        assert_eq!(string_nocase_compare("Apple", "apple"), 0);
        assert_eq!(string_nocase_compare("apple", "Banana"), -1);
        assert_eq!(string_nocase_compare("Banana", "apple"), 1);
    }
}
